package twi;

import java.util.ArrayList;
import java.util.HashMap;

import twi.filter.Filter;
import twi.query.Query;
import twi.result.DefaultResult;
import twi.result.QueryResult;
import twi_project.TWI;

import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;

public class QueryManager {

	public static boolean showClasses = true;
	public static boolean showInstance = true;
	public static boolean showLiterals = true;
	public static String filterText = "";
	
	private static HashMap<String, String> instances = null;
	private static HashMap<String, String> classes = null;
	
	
	static class ClassFilter implements Filter{
		
		@Override
		public boolean isValid(RDFNode node) {
			if (!showClasses){
				if (classes.containsKey(node.toString()))
					return false;
				return true;
			}
			return true;
		}

		@Override
		public void decodeString(String filterString) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public String encodeString() {
			// TODO Auto-generated method stub
			return null;
		}
		
	}

	static class InstanceFilter implements Filter{

		@Override
		public boolean isValid(RDFNode node) {
			if (!showInstance){
				if (instances.containsKey(node.toString()))
					return false;
				return true;
			}
			return true;
		}

		@Override
		public void decodeString(String filterString) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public String encodeString() {
			// TODO Auto-generated method stub
			return null;
		}
		
	}

	static class LiteralFilter implements Filter{

		@Override
		public boolean isValid(RDFNode node) {
			if (!showLiterals){
				if (node.isLiteral())
					return false;
			}
			return true;
		}

		@Override
		public void decodeString(String filterString) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public String encodeString() {
			// TODO Auto-generated method stub
			return null;
		}
		
	}

	
	
	
	private static Filter classFilter = new ClassFilter();
	private static Filter instanceFilter = new InstanceFilter();
	private static Filter literalFilter = new LiteralFilter();
	
	public static QueryResult executeQuery(Query query) {
		ResultSet rs = executeSparqlQuery(query);
		DefaultResult result = new DefaultResult(query, rs);
		return result;
	}

	private static ResultSet executeSparqlQuery(Query query) {
		createFilter(query);
		OWLModel model = query.getModel();
		if (model == null)
			throw new NullPointerException("OWLModel for query may not be null");

		com.hp.hpl.jena.query.Query q = QueryFactory.create(query
				.getSPARQLString());
		QueryExecution qexec = QueryExecutionFactory.create(q, model);
		ResultSet rs = qexec.execSelect();
		return rs;
	}
	
	
	private static void createFilter(Query query){
		
		class EqualsFilter implements Filter{
			ArrayList<String> words = new ArrayList<String>();
			boolean inclusive = false;
			private String URI = TWI.getInstance().getOntologieModel().getBasePrefix();
			private boolean equals = true;
			
			public EqualsFilter(boolean inclusive, boolean equals, ArrayList<String> w){
				this.inclusive = inclusive;
				this.words = w;
				this.equals  = equals;
			}
			@Override
			public boolean isValid(RDFNode node) {
				if (node == null)
					return true;
				String n = Utils.getLocalName(node);
				for (int i =0 ; i < words.size(); i++){
					if (this.equals){
						if (n.equals(words.get(i)))
							return !inclusive;
						if ((URI+n).equals(words.get(i)))
							return !inclusive;
					}else{
						if (n.contains(words.get(i)))
							return !inclusive;
						if ((URI+n).contains(words.get(i)))
							return !inclusive;
					}
				}
				return false;
			}

			@Override
			public void decodeString(String filterString) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public String encodeString() {
				// TODO Auto-generated method stub
				return null;
			}
			
		}
		
		
		if (instances == null)
			setup();
		if (!showClasses)
			query.addFilter(classFilter);
		if (!showInstance)
			query.addFilter(instanceFilter);
		if (!showLiterals)
			query.addFilter(literalFilter);
		
		ArrayList<String> equalsInclusive = new ArrayList<String>();
		ArrayList<String> equalsExclusive = new ArrayList<String>();
		ArrayList<String> containsInclusive = new ArrayList<String>();
		ArrayList<String> containsExclusive = new ArrayList<String>();
		
		String[] split = filterText.split(" ");
		if (split.length <= 0)
			return ;
		for (int i = 0; i  < split.length; i++){
			if (split[i].startsWith("~+"))
				containsInclusive.add(split[i].replace("~+", ""));
			else if (split[i].startsWith("~-"))
				containsExclusive.add(split[i].replace("~-", ""));
			else if (split[i].startsWith("+"))
				equalsInclusive.add(split[i].replace("+", ""));
			else if (split[i].startsWith("-"))
				equalsExclusive.add(split[i].replace("-", ""));
		}
		
		if (!equalsExclusive.isEmpty()){
			query.addFilter(new EqualsFilter(false, true, equalsExclusive));
		}
		if (!equalsInclusive.isEmpty())
			query.addFilter(new EqualsFilter(true, true, equalsInclusive));
		if (!containsExclusive.isEmpty())
			query.addFilter(new EqualsFilter(false, false, containsExclusive));
		if (!containsInclusive.isEmpty())
			query.addFilter(new EqualsFilter(true, false, containsInclusive));
	}

	private static void setup() {
		OWLModel model = TWI.getInstance().getOntologieModel();
		
		classes = new HashMap<String, String>();
		instances = new HashMap<String, String>();
		
		ExtendedIterator iter = model.listClasses();
		while(iter.hasNext()){
			String v = iter.next().toString();
			classes.put(v, v);
		}
		
		iter = model.listIndividuals();
		while(iter.hasNext()){
			String v = iter.next().toString();
			instances.put(v, v);
		}
		
	}
}
